package com.fnic.pearl.scheduler.util.sys;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.management.ManagementFactory;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import com.sun.management.OperatingSystemMXBean;

/**
 * 
 * @Title:系统负载获取
 * @Description:
 * @Author:吉
 * @Since:2016年5月3日
 * @Version:1.1.0
 */
@SuppressWarnings("restriction")
public class SysInfo {
	private static final int CPUTIME = 30;
	private static final int PERCENT = 100;
	private static String linuxVersion = "2.6";
	private static final int FAULTLENGTH = 10;

	public static Map<String, Object> memory() {
		OperatingSystemMXBean osmb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
		int core = osmb.getAvailableProcessors();
		long maxPhsicalMemroy = osmb.getTotalPhysicalMemorySize() / 1024 / 1024;
		long freeMemory = osmb.getFreePhysicalMemorySize() / 1024 / 1024;
		long usedJVM = Runtime.getRuntime().maxMemory() / 1024 / 1024;
		long otherUsedMemory = maxPhsicalMemroy - usedJVM - freeMemory;
		Map<String, Object> series = new HashMap<String, Object>();
		series.put("系统可用核心数", core);
		series.put("系统总内存", maxPhsicalMemroy + "M");
		series.put("系统空余内存", freeMemory + "M");
		// series.put("jvm|内存", usedJVM + "M");
		series.put("系统其他程序占用内存", otherUsedMemory + "M");
		return series;
	}

	public static Map<String, Object> getJvmMemoryData() {
		Map<String, Object> series = new HashMap<String, Object>();
		long total = Runtime.getRuntime().totalMemory() / 1024 / 1024; // 当前jvm占用内存总数，相当jvm已经使用的内存和freeMemory的和
		long max = Runtime.getRuntime().maxMemory() / 1024 / 1024;// 最大可用jvm内存
		long free = Runtime.getRuntime().freeMemory() / 1024 / 1024;// 为当前JVM空闲内存，因为JVM只有在需要内存时才占用物理内存使用，所以该值一般情况下都很小，而
		long reallyFree = max - total + free;
		// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		// series.put("value", (double) reallyFree / max);
		// series.put("text", "最大Jvm可用内存:" + max + "M, Jvm空闲内存:" + free + "M, "
		// + "当前Jvm内存:" + total + "M|");
		series.put("Jvm最大可用内存", max + "M");
		series.put("Jvm空闲内存", free + "M");
		series.put("Jvm当前占用", total - free + "M");
		series.put("Jvm当前总内存(空闲+使用)", total + "M");
		return series;
	}

	public static Map<String, Object> getCpuData() {
		Map<String, Object> series = new HashMap<String, Object>();
		double cpuRatio = 0;
		// 操作系统
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String osName = System.getProperty("os.name");
		if (osName.toLowerCase().startsWith("windows")) {
			cpuRatio = getCpuRatioForWindows();
		} else {
			cpuRatio = getCpuRateForLinux();
		}
		// series.put("value", cpuRatio);
		series.put("Cpu瞬时使用率", cpuRatio + "%");
		return series;
	}
	// ------------------------------------------private --------------

	private static double getCpuRatioForWindows() {
		try {
			String procCmd = System.getenv("windir") + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,"
					+ "KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";
			// 取进程信息
			long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd));
			Thread.sleep(CPUTIME);
			long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd));
			if (c0 != null && c1 != null) {
				long idletime = c1[0] - c0[0];
				long busytime = c1[1] - c0[1];
				return Double.valueOf(PERCENT * (busytime) / (busytime + idletime)).doubleValue();
			} else {
				return 0.0;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			return 0.0;
		}
	}

	private static double getCpuRateForLinux() {
		InputStream is = null;
		InputStreamReader isr = null;
		BufferedReader brStat = null;
		StringTokenizer tokenStat = null;
		try {
			System.out.println("Get usage rate of CUP , linux version: " + linuxVersion);

			Process process = Runtime.getRuntime().exec("top -b -n 1");
			is = process.getInputStream();
			isr = new InputStreamReader(is);
			brStat = new BufferedReader(isr);

			if (linuxVersion.equals("2.4")) {
				brStat.readLine();
				brStat.readLine();
				brStat.readLine();
				brStat.readLine();

				tokenStat = new StringTokenizer(brStat.readLine());
				tokenStat.nextToken();
				tokenStat.nextToken();
				String user = tokenStat.nextToken();
				tokenStat.nextToken();
				String system = tokenStat.nextToken();
				tokenStat.nextToken();
				String nice = tokenStat.nextToken();

				System.out.println(user + " , " + system + " , " + nice);

				user = user.substring(0, user.indexOf("%"));
				system = system.substring(0, system.indexOf("%"));
				nice = nice.substring(0, nice.indexOf("%"));

				float userUsage = new Float(user).floatValue();
				float systemUsage = new Float(system).floatValue();
				float niceUsage = new Float(nice).floatValue();

				return (userUsage + systemUsage + niceUsage) / 100;
			} else {
				brStat.readLine();
				brStat.readLine();

				tokenStat = new StringTokenizer(brStat.readLine());
				tokenStat.nextToken();
				tokenStat.nextToken();
				tokenStat.nextToken();
				tokenStat.nextToken();
				tokenStat.nextToken();
				tokenStat.nextToken();
				tokenStat.nextToken();
				String cpuUsage = tokenStat.nextToken();
				System.out.println("CPU idle : " + cpuUsage);
				Float usage = new Float(cpuUsage.substring(0, cpuUsage.indexOf("%")));

				return (1 - usage.floatValue() / 100);
			}

		} catch (IOException ioe) {
			System.out.println(ioe.getMessage());
			freeResource(is, isr, brStat);
			return 1;
		} finally {
			freeResource(is, isr, brStat);
		}
	}

	private static void freeResource(InputStream is, InputStreamReader isr, BufferedReader br) {
		try {
			if (is != null)
				is.close();
			if (isr != null)
				isr.close();
			if (br != null)
				br.close();
		} catch (IOException ioe) {
			System.out.println(ioe.getMessage());
		}
	}

	private static long[] readCpu(final Process proc) {
		long[] retn = new long[2];
		try {
			proc.getOutputStream().close();
			InputStreamReader ir = new InputStreamReader(proc.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line = input.readLine();
			if (line == null || line.length() < FAULTLENGTH) {
				return null;
			}
			int capidx = line.indexOf("Caption");
			int cmdidx = line.indexOf("CommandLine");
			int rocidx = line.indexOf("ReadOperationCount");
			int umtidx = line.indexOf("UserModeTime");
			int kmtidx = line.indexOf("KernelModeTime");
			int wocidx = line.indexOf("WriteOperationCount");
			long idletime = 0;
			long kneltime = 0;
			long usertime = 0;
			while ((line = input.readLine()) != null) {
				if (line.length() < wocidx) {
					continue;
				}
				// 字段出现顺序：Caption,CommandLine,KernelModeTime,ReadOperationCount,
				// ThreadCount,UserModeTime,WriteOperation
				String caption = Bytes.substring(line, capidx, cmdidx - 1).trim();
				String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim();
				if (cmd.indexOf("wmic.exe") >= 0) {
					continue;
				}
				// log.info("line="+line);
				if (caption.equals("System Idle Process") || caption.equals("System")) {
					idletime += Long.valueOf(Bytes.substring(line, kmtidx, rocidx - 1).trim()).longValue();
					idletime += Long.valueOf(Bytes.substring(line, umtidx, wocidx - 1).trim()).longValue();
					continue;
				}

				kneltime += Long.valueOf(Bytes.substring(line, kmtidx, rocidx - 1).trim()).longValue();
				usertime += Long.valueOf(Bytes.substring(line, umtidx, wocidx - 1).trim()).longValue();
			}
			retn[0] = idletime;
			retn[1] = kneltime + usertime;
			return retn;
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public static void main(String[] args) {

		System.out.println(SysInfo.getJvmMemoryData());
		System.out.println(getCpuData());
	}
}
